package com.swinginwind.flexutils.components {
	import com.greensock.TweenLite;
	import com.greensock.easing.Expo;
	
	import flash.display.DisplayObject;
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.events.MouseEvent;
	import flash.geom.Point;
	import flash.text.TextLineMetrics;
	
	import mx.containers.Panel;
	import mx.controls.Button;
	import mx.core.EdgeMetrics;
	import mx.core.IInvalidating;
	import mx.core.mx_internal;
	import mx.events.ChildExistenceChangedEvent;
	import mx.managers.CursorManager;
	import mx.styles.StyleProxy;
	
	[Event(name="resizeStart",type="flash.events.Event")]
	[Event(name="resizing",type="flash.events.Event")]
	[Event(name="resizeEnd",type="flash.events.Event")]
	[Event(name="moveStart",type="flash.events.Event")]
	[Event(name="moving",type="flash.events.Event")]
	[Event(name="moveEnd",type="flash.events.Event")]
	[Event(name="minimize",type="flash.events.Event")]
	[Event(name="maximize",type="flash.events.Event")]
	[Event(name="normal",type="flash.events.Event")]
	[Event(name="close",type="flash.events.Event")]
	
	[Style(name="resizeCursor",type="Class")]
	[Style(name="resizeIcon",type="Class")]
	
	[Style(name="minButtonSkin",type="Class")]
	[Style(name="minButtonUpSkin",type="Class")]
	[Style(name="minButtonOverSkin",type="Class")]
	[Style(name="minButtonDownSkin",type="Class")]
	[Style(name="minButtonDisabledSkin",type="Class")]
	
	[Style(name="normalButtonSkin",type="Class")]
	[Style(name="normalButtonUpSkin",type="Class")]
	[Style(name="normalButtonOverSkin",type="Class")]
	[Style(name="normalButtonDownSkin",type="Class")]
	[Style(name="normalButtonDisabledSkin",type="Class")]
	
	[Style(name="maxButtonSkin",type="Class")]
	[Style(name="maxButtonUpSkin",type="Class")]
	[Style(name="maxButtonOverSkin",type="Class")]
	[Style(name="maxButtonDownSkin",type="Class")]
	[Style(name="maxButtonDisabledSkin",type="Class")]
	
	public class EWindow extends Panel {
		public static const MINIMIZE:String="minimize";
		public static const MAXIMIZE:String="maximize";
		public static const NORMAL:String="normal";
		public static const CLOSE:String="close";
		public static const RESIZE_START:String="resizeStart";
		public static const RESIZING:String="resizing";
		public static const RESIZE_END:String="resizeEnd";
		public static const MOVE_START:String="moveStart";
		public static const MOVING:String="moving";
		public static const MOVE_END:String="moveEnd";
		
		public static var minimizeWidth:Number=800;
		public static var minimizeHeight:Number=300;
		
		private var minBtn:Button;
		private var normalBtn:Button;
		private var maxBtn:Button;
		private var closeBtn:Button;
		private var resizeObj:Sprite;
		
		public var normalWidth:Number;
		public var normalHeight:Number;
		public var normalX:Number;
		public var normalY:Number;
		
		public var canShowEffect:Boolean=true;
		public var maximiseEnabled:Boolean=true;
		
		private var _controlButtonGap:Number=3;
		private var _controlButtonEnableds:Array=[true,true,true];
		private var _controlButtonVisibles:Array=[true,true,true];
		private var _controlButtonStatus:String=NORMAL;
		private var _resizeable:Boolean=true;
		
		[Inspectable(category="General")]
		public var dragEnabled:Boolean=true;
		[Inspectable(category="General")]
		public var autoMoveToTop:Boolean=true;
		
		private var ResizeIcon:Class;
		
		public function EWindow() {
			super();
			mx_internal::_showCloseButton=true;
			
			minWidth=minimizeWidth;
			minHeight=minimizeHeight;
			
			addEventListener("widthChanged",posSizeChangedEvt);
			addEventListener("heightChanged",posSizeChangedEvt);
			addEventListener("xChanged",posSizeChangedEvt);
			addEventListener("yChanged",posSizeChangedEvt);
			addEventListener(ChildExistenceChangedEvent.CHILD_ADD,addToStageEvt);
			addEventListener(MouseEvent.MOUSE_DOWN,thisMouseDown);
		}
		private function addToStageEvt(e:ChildExistenceChangedEvent):void{
			if(title!="") return;
			if(getChildAt(0).hasOwnProperty("label")) title=getChildAt(0)["label"];
		}
		private function thisMouseDown(e:MouseEvent):void{
			if(autoMoveToTop){
				if(parent&&parent.getChildIndex(this)!=parent.numChildren-1) parent.setChildIndex(this,parent.numChildren-1);
			}
		}
		
		override public function set title(value:String):void{
			super.title=value;
			invalidateDisplayList();
		}
		
		override protected function createChildren():void{
			super.createChildren();
			
			if(!minBtn){
				minBtn=new Button;
				minBtn.buttonMode=true;
				minBtn.useHandCursor=true;
				minBtn.styleName = new StyleProxy(this, minButtonStyleFilters);
				minBtn.mx_internal::upSkinName = "minButtonUpSkin";
				minBtn.mx_internal::overSkinName = "minButtonOverSkin";
				minBtn.mx_internal::downSkinName = "minButtonDownSkin";
				minBtn.mx_internal::disabledSkinName = "minButtonDisabledSkin";
				minBtn.mx_internal::skinName = "minButtonSkin";
				minBtn.explicitWidth=minBtn.explicitHeight=16;
				minBtn.addEventListener(MouseEvent.CLICK,handleButtonEvt);
				titleBar.addChild(minBtn);
			}
			if(!maxBtn){
				maxBtn=new Button;
				maxBtn.buttonMode=true;
				maxBtn.useHandCursor=true;
				maxBtn.styleName = new StyleProxy(this, maxButtonStyleFilters);
				maxBtn.mx_internal::upSkinName = "maxButtonUpSkin";
				maxBtn.mx_internal::overSkinName = "maxButtonOverSkin";
				maxBtn.mx_internal::downSkinName = "maxButtonDownSkin";
				maxBtn.mx_internal::disabledSkinName = "maxButtonDisabledSkin";
				maxBtn.mx_internal::skinName = "maxButtonSkin";
				maxBtn.explicitWidth=maxBtn.explicitHeight=16;
				maxBtn.addEventListener(MouseEvent.CLICK,handleButtonEvt);
				titleBar.addChild(maxBtn);
			}
			if(!normalBtn){
				normalBtn=new Button;
				normalBtn.buttonMode=true;
				normalBtn.useHandCursor=true;
				normalBtn.styleName = new StyleProxy(this, normalButtonStyleFilters);
				normalBtn.mx_internal::upSkinName = "normalButtonUpSkin";
				normalBtn.mx_internal::overSkinName = "normalButtonOverSkin";
				normalBtn.mx_internal::downSkinName = "normalButtonDownSkin";
				normalBtn.mx_internal::disabledSkinName = "normalButtonDisabledSkin";
				normalBtn.mx_internal::skinName = "normalButtonSkin";
				normalBtn.explicitWidth=normalBtn.explicitHeight=16;
				normalBtn.addEventListener(MouseEvent.CLICK,handleButtonEvt);
				titleBar.addChild(normalBtn);
			}
			if(!closeBtn){
				closeBtn=mx_internal::closeButton;
				closeBtn.buttonMode=true;
				closeBtn.useHandCursor=true;
				closeBtn.explicitWidth=closeBtn.explicitHeight=16;
				closeBtn.addEventListener(MouseEvent.CLICK,handleButtonEvt);
			}
			
			titleBar.doubleClickEnabled=true;
			titleBar.addEventListener(MouseEvent.MOUSE_DOWN,handleTitleBarEvt);
			titleBar.addEventListener(MouseEvent.DOUBLE_CLICK,handleTitleBarEvt);
			
			if(_controlButtonVisibles) conBtnVisibles=_controlButtonVisibles;
		}
		
		override protected function measure():void{
			super.measure();
			
			measuredWidth=150;
			measuredHeight=100;
		}
		
		private var _conButtonFirstTimeInit:Boolean=true;
		override protected function updateDisplayList(w:Number, h:Number):void{
			super.updateDisplayList(w,h);
			
			var vm:EdgeMetrics=borderMetrics;
			var lm:TextLineMetrics=measureText(title);
			
			if(_conButtonFirstTimeInit){
				_conButtonFirstTimeInit=false;
				closeBtn.width=closeBtn.getExplicitOrMeasuredWidth();
				closeBtn.height=closeBtn.getExplicitOrMeasuredHeight();
				maxBtn.width=maxBtn.getExplicitOrMeasuredWidth();
				maxBtn.height=maxBtn.getExplicitOrMeasuredHeight();
				normalBtn.width=normalBtn.getExplicitOrMeasuredWidth();
				normalBtn.height=normalBtn.getExplicitOrMeasuredHeight();
				minBtn.width=minBtn.getExplicitOrMeasuredWidth();
				minBtn.height=minBtn.getExplicitOrMeasuredHeight();
			}
			
			var headerHeight:Number=getStyle("headerHeight");
			if(!headerHeight) headerHeight=minimizeHeight;
			var tHeight:Number=Math.max(lm.height,closeBtn.height,normalBtn.height,minBtn.height,maxBtn.height,headerHeight,titleBar.height);
			
			closeBtn.x=w-closeBtn.width-vm.right;
			maxBtn.x=normalBtn.x=closeBtn.x-normalBtn.width-_controlButtonGap;
			minBtn.x=normalBtn.x-minBtn.width-_controlButtonGap;
			closeBtn.y=(tHeight-closeBtn.height)/2;
			maxBtn.y=normalBtn.y=(tHeight-normalBtn.height)/2;
			minBtn.y=(tHeight-minBtn.height)/2;
			
			var xOffset:Number=minBtn.width+normalBtn.width+closeBtn.width+2*_controlButtonGap;
			if(titleIcon) mx_internal::titleIconObject.x-=10-vm.left;
			titleTextField.x-=10-vm.left;
			if(statusTextField) statusTextField.x-=xOffset;
			titleTextField.setActualSize(titleTextField.width-xOffset,titleTextField.height);
			
			if(_resizeable){
				if(!resizeObj){
					resizeObj=new Sprite;
					resizeObj.addEventListener(MouseEvent.ROLL_OVER,handleResizeBtnEvt);
					rawChildren.addChild(resizeObj);
				}
				var cls:Class=getStyle("resizeIcon") as Class;
				if(cls!=null&&_currentReiszeClass!=cls){
					while(resizeObj.numChildren>0) resizeObj.removeChildAt(0);
					var obj:DisplayObject=(new cls) as DisplayObject;
					resizeObj.addChild(obj);
				}
				if(rawChildren.getChildAt(rawChildren.numChildren-1)!=resizeObj) rawChildren.setChildIndex(resizeObj,rawChildren.numChildren-1);
				resizeObj.x=w-resizeObj.width;
				resizeObj.y=h-resizeObj.height;
			}else{
				if(resizeObj){
					resizeObj.removeEventListener(MouseEvent.ROLL_OVER,handleResizeBtnEvt);
					rawChildren.removeChild(resizeObj);
					resizeObj=null;
				}
			}
			
			minBtn.visible=Boolean(_controlButtonVisibles[0]);
			normalBtn.visible=maxBtn.visible=Boolean(_controlButtonVisibles[1]);
			closeBtn.visible=Boolean(_controlButtonVisibles[2]);
			if(!_controlButtonVisibles[2]){
				normalBtn.x=maxBtn.x=normalBtn.x+closeBtn.width+_controlButtonGap;
				minBtn.x+=closeBtn.width+_controlButtonGap;
			}
			if(!_controlButtonVisibles[1]){
				minBtn.x+=normalBtn.width+_controlButtonGap;
			}
			
			if(_controlButtonVisibles[1]&&_controlButtonStatus){
				switch(_controlButtonStatus){
					case MINIMIZE:{
						maxBtn.visible=true;
						normalBtn.visible=false;
						if(_resizeable) resizeObj.visible=false;
						break;
					}
					case MAXIMIZE:{
						maxBtn.visible=true;
						normalBtn.visible=false;
						if(_resizeable) resizeObj.visible=false;
						break;
					}
					case NORMAL:{
						maxBtn.visible=false;
						normalBtn.visible=true;
						if(_resizeable) resizeObj.visible=true;
						break;
					}
				}
			}
			
			if(_controlButtonEnableds_changed){
				_controlButtonEnableds_changed=false;
				if(_controlButtonEnableds){
					minBtn.enabled=Boolean(_controlButtonEnableds[0]);
					normalBtn.enabled=maxBtn.enabled=Boolean(_controlButtonEnableds[1]);
					closeBtn.enabled=Boolean(_controlButtonEnableds[2]);
				}
			}
		}
		private var _currentReiszeClass:Class;
		
		private function posSizeChangedEvt(e:Event):void{
			if(e.type=="widthChanged"){
				if(_controlButtonStatus==NORMAL) normalWidth=width;
			}else if(e.type=="heightChanged"){
				if(_controlButtonStatus==NORMAL) normalHeight=height;
			}else if(e.type=="xChanged"){
				if(_controlButtonStatus!=MAXIMIZE) normalX=x;
			}else if(e.type=="yChanged"){
				if(_controlButtonStatus!=MAXIMIZE) normalY=y;
			}
		}
		
		private function handleTitleBarEvt(e:MouseEvent):void{
			if(e.type==MouseEvent.MOUSE_DOWN){
				if(e.target is Button) return;
				
				if(dragEnabled&&_controlButtonStatus!=MAXIMIZE){
					startDrag();
					dispatchEvent(new Event(MOVE_START));
					if(systemManager){
						systemManager.addEventListener(MouseEvent.MOUSE_MOVE,handleTitleBarEvt);
						systemManager.addEventListener(MouseEvent.MOUSE_UP,handleTitleBarEvt);
					}
				}
			}else if(e.type==MouseEvent.MOUSE_UP){
				if(systemManager){
					systemManager.removeEventListener(MouseEvent.MOUSE_MOVE,handleTitleBarEvt);
					systemManager.removeEventListener(MouseEvent.MOUSE_UP,handleTitleBarEvt);
				}
				stopDrag();
				if(parent){
					if(y<-15) y=0;
					else if(y>parent.height-minimizeHeight) y=parent.height-minimizeHeight;
					if(x<width/2*(-1)) x=width/2*(-1);
					else if(x>parent.width-width/2) x=parent.width-width/2;
				}
				dispatchEvent(new Event(MOVE_END));
			}else if(e.type==MouseEvent.MOUSE_MOVE){
				dispatchEvent(new Event(MOVING));
				var p:IInvalidating = parent as IInvalidating;
				if (p) p.invalidateDisplayList();
			}else if(e.type==MouseEvent.DOUBLE_CLICK){
				if(Boolean(_controlButtonEnableds[1])==false) return;
				if(e.target is Button) return;
				if(_controlButtonStatus==NORMAL){
					controlButtonStatus=MAXIMIZE;
				}else{
					controlButtonStatus=NORMAL;
				}
			}
		}
		
		private function handleButtonEvt(e:MouseEvent):void{
			var obj:DisplayObject=e.currentTarget as DisplayObject;
			if(obj==minBtn){
				controlButtonStatus=MINIMIZE;
			}else if(obj==maxBtn){
				controlButtonStatus=NORMAL;
			}else if(obj==normalBtn){
				controlButtonStatus=MAXIMIZE;
			}else if(obj==closeBtn){
				if(parent) parent.removeChild(this);
				dispatchEvent(new Event(CLOSE));
			}
		}
		
		private var _resizeCursorId:int;
		private function handleResizeBtnEvt(e:MouseEvent):void{
			if(e.type==MouseEvent.ROLL_OVER){
				resizeObj.addEventListener(MouseEvent.ROLL_OUT,handleResizeBtnEvt);
				resizeObj.addEventListener(MouseEvent.MOUSE_DOWN,handleResizeBtnEvt);
				var cursor:Class=getStyle("resizeCursor");
				if(cursor!=null) _resizeCursorId=CursorManager.setCursor(cursor,2,-4,-4);
			}else if(e.type==MouseEvent.ROLL_OUT){
				resizeObj.removeEventListener(MouseEvent.ROLL_OUT,handleResizeBtnEvt);
				resizeObj.removeEventListener(MouseEvent.MOUSE_DOWN,handleResizeBtnEvt);
				CursorManager.removeCursor(_resizeCursorId);
			}else if(e.type==MouseEvent.MOUSE_DOWN){
				resizeObj.addEventListener(MouseEvent.MOUSE_MOVE,handleResizeBtnEvt);
				resizeObj.addEventListener(MouseEvent.MOUSE_UP,handleResizeBtnEvt);
				resizeObj.stage.addEventListener(MouseEvent.MOUSE_MOVE,handleResizeBtnEvt);
				resizeObj.stage.addEventListener(MouseEvent.MOUSE_UP,handleResizeBtnEvt);
				dispatchEvent(new Event(RESIZE_START));
			}else if(e.type==MouseEvent.MOUSE_UP){
				resizeObj.removeEventListener(MouseEvent.MOUSE_MOVE,handleResizeBtnEvt);
				resizeObj.removeEventListener(MouseEvent.MOUSE_UP,handleResizeBtnEvt);
				resizeObj.stage.removeEventListener(MouseEvent.MOUSE_MOVE,handleResizeBtnEvt);
				resizeObj.stage.removeEventListener(MouseEvent.MOUSE_UP,handleResizeBtnEvt);
				dispatchEvent(new Event(RESIZE_END));
			}else if(e.type==MouseEvent.MOUSE_MOVE){
				var pt:Point=new Point(e.stageX,e.stageY);
				pt=globalToLocal(pt);
				pt.offset(4,4);
				if(pt.x<minimizeWidth) pt.x=minimizeWidth;
				if(pt.y<minimizeHeight) pt.y=minimizeHeight;
				if(pt.x==minimizeWidth&&pt.y==minimizeHeight) return;
				width=pt.x;
				height=pt.y;
				dispatchEvent(new Event(RESIZING));
			}
		}
		
		private var _minButtonStyleFilters:Object = {
			"minButtonUpSkin" : "minButtonUpSkin", 
			"minButtonOverSkin" : "minButtonOverSkin",
			"minButtonDownSkin" : "minButtonDownSkin",
			"minButtonDisabledSkin" : "minButtonDisabledSkin",
			"minButtonSkin" : "minButtonSkin"
		};
		private var _normalButtonStyleFilters:Object = {
			"normalButtonUpSkin" : "normalButtonUpSkin", 
			"normalButtonOverSkin" : "normalButtonOverSkin",
			"normalButtonDownSkin" : "normalButtonDownSkin",
			"normalButtonDisabledSkin" : "normalButtonDisabledSkin",
			"normalButtonSkin" : "normalButtonSkin"
		};
		private var _maxButtonStyleFilters:Object = {
			"maxButtonUpSkin" : "maxButtonUpSkin", 
			"maxButtonOverSkin" : "maxButtonOverSkin",
			"maxButtonDownSkin" : "maxButtonDownSkin",
			"maxButtonDisabledSkin" : "maxButtonDisabledSkin",
			"maxButtonSkin" : "maxButtonSkin"
		};
		
		private function get minButtonStyleFilters():Object{ return _minButtonStyleFilters; }
		private function get normalButtonStyleFilters():Object{ return _normalButtonStyleFilters; }
		private function get maxButtonStyleFilters():Object{ return _maxButtonStyleFilters; }
		
		[Inspectable(category="General", enumeration="minimize,maximize,normal",defaultValue="normal")]
		public function set controlButtonStatus(val:String):void{
			switch(val){
				case MINIMIZE:{
					_controlButtonStatus=MINIMIZE;
					var toX:Number=normalX;
					if(toX+minimizeWidth<minimizeWidth/2) toX=-minimizeWidth/2;
					if(canShowEffect){
						TweenLite.to(this,0.3,{x:toX,y:normalY,width:minimizeWidth,height:minimizeHeight,ease:Expo.easeOut});
					}else{
						x=toX;
						y=normalY;
						width=minimizeWidth;
						height=minimizeHeight;
					}
					normalBtn.visible=false;
					maxBtn.visible=true;
					if(_resizeable) resizeObj.visible=false;
					dispatchEvent(new Event(MINIMIZE));
					break;
				}
				case MAXIMIZE:{
					if(!maximiseEnabled){
//						normalBtn.visible=true;
//						maxBtn.visible=false;
//						if(_resizeable) resizeObj.visible=true;
						break;
					}
					_controlButtonStatus=MAXIMIZE;
					if(canShowEffect){
						TweenLite.to(this,0.3,{x:0,y:0,width:parent.width,height:parent.height,ease:Expo.easeOut});
					}else{
						x=y=0;
						width=parent.width;
						height=parent.height;
					}
					normalBtn.visible=false;
					maxBtn.visible=true;
					if(_resizeable) resizeObj.visible=false;
					dispatchEvent(new Event(MAXIMIZE));
					break;
				}
				case NORMAL:{
					_controlButtonStatus=NORMAL;
					if(canShowEffect){
						TweenLite.to(this,0.3,{x:normalX,y:normalY,width:normalWidth,height:normalHeight,ease:Expo.easeOut});
					}else{
						x=normalX;
						y=normalY;
						width=normalWidth;
						height=normalHeight;
					}
					normalBtn.visible=true;
					maxBtn.visible=false;
					if(_resizeable) resizeObj.visible=true;
					dispatchEvent(new Event(NORMAL));
					break;
				}
			}
			
		}
		public function get controlButtonStatus():String{
			return _controlButtonStatus;
		}
		public function get isMaxisize():Boolean{
			return _controlButtonStatus==MAXIMIZE;
		}
		
		private var _controlButtonEnableds_changed:Boolean=true;
		public function set controlButtonEnableds(val:Array):void{
			_controlButtonEnableds_changed=true;
			_controlButtonEnableds=val;
			invalidateDisplayList();
		}
		public function get controlButtonEnableds():Array{
			return _controlButtonEnableds;
		}
		
		[Inspectable(category="General")]
		public function set controlButtonGap(val:Number):void{
			_controlButtonGap=val;
			invalidateDisplayList();
		}
		public function get controlButtonGap():Number{
			return _controlButtonGap;
		}
		
		[Inspectable(category="General")]
		public function set resizeable(val:Boolean):void{
			_resizeable=val;
			invalidateDisplayList();
		}
		public function get resizeable():Boolean{
			return _resizeable;
		}
		
		//控制按钮的可见性
		public function set conBtnVisibles(arr:Array):void{
			_controlButtonVisibles=arr;
			invalidateDisplayList();
		}
	}
}